#include "ubvm_2darray.h"
#include "DIVA_Manager.h"
#include "xParameterPack.h"
#include "vmLibrary.h"

#include <sstream>

ubvm_2darray::ubvm_2darray( xParameterPack xpp ):DIVA_VM(xpp){
	int default_port_number = vmLibrary::instance().get_vm_default_input_parameters().size() ;
	assert(xpp.no ==default_port_number+3);
	// name = xpp.paras[0].val_string ;
	_rows = xpp.paras[default_port_number].val_int_ptr ;
	_columns = xpp.paras[default_port_number+1].val_int_ptr ;
	_child_vms = xpp.paras[default_port_number+2].val_vms ;
	
	assert(_rows != NULL);
	assert(_columns != NULL);
	assert((*_rows) != 0 && (*_columns) != 0); // if this is the case 
	                                    // user forget to set the attributes

	init_default_parameters(); // must be called 
}	

void ubvm_2darray::load_3Dresources() {

	Ogre::Vector3 max = Ogre::Vector3(0,0,0);
	VL_arrangeVMs(_child_vms);
	max = VL_computeMaxBoundingsize(_child_vms,DO_NOTHING,DO_NOTHING,Z_Max);
	//-----------------------------------------------------------------------

	std::vector<DIVA_VM*>::iterator itr = _child_vms.begin();
	assert(itr != _child_vms.end());
	itr = _child_vms.begin() ;

	Ogre::Vector3 sz = (*itr)->getActualSize();
	max.x = sz.x * (*_columns) ;
	max.y = sz.y * (*_rows) ;	

	Ogre::Real top_left_y =  max.y/2  ;  // starting location is at the top-left corner from the origin
	Ogre::Real top_left_x = -max.x/2 ;
	Ogre::Real bottom_z   = -max.z/2 ;
	sz = (*itr)->getActualSize(); // get the size of a child VM
	Ogre::Real x = top_left_x + sz.x/2 ;
	Ogre::Real y = top_left_y - sz.y/2 ;

	int columnno = 0 ;
	for (itr = _child_vms.begin();itr != _child_vms.end(); itr++) {
		// set the position of child vm (relative to its parent)
		DIVA_VM *p = (*itr);
		sz = p->getActualSize(); // get the size of a child V
		Ogre::Real d = max.z/2 - sz.z/2 ;
		// Vector3 childscale = (*itr)->getScale();

		p->setPosition(Ogre::Vector3(x,y,-d));
		x = x + sz.x  ;
		columnno ++ ;
		if (columnno == (*_columns)) {
			columnno = 0 ;
			y = y - sz.y  ;
			x = top_left_x + sz.x/2 ;
		}
	}


}
void ubvm_2darray::set_default_values() {
	_vm_rx_val = 0 ;
	_vm_ry_val = 0 ;
	_vm_rz_val = 0 ;

	Ogre::Vector3 sz = this->getActualSize();
	_vm_init_sizex = sz.x ;
	_vm_init_sizey = sz.y ;
	_vm_init_sizez = sz.z ;

	_vm_sizex_val = sz.x ;
	_vm_sizey_val = sz.y ;
	_vm_sizez_val = sz.z ;

	_vm_sizexscale_val = 1.0 ;
	_vm_sizeyscale_val = 1.0 ;
	_vm_sizezscale_val = 1.0 ;

	_vm_r_val = 0.3;  // white color but with transparency 0.1
	_vm_g_val = 0.3;
	_vm_b_val = 0.3;
	_vm_transparency_val = 1.0 ;

	_vm_yaw_val = 0 ;
	_vm_pitch_val = 0 ;
	_vm_roll_val = 0 ;

}
void ubvm_2darray::reg_event_entity() {

	// register the relation of the entity and vm in diva manager
	// When this entity is clicked, mouse/keyboard VM will be passed to this VM
	// By default it can be only one entity representing this VM
}
void ubvm_2darray::init_private_attrs_started() {
	
}
void ubvm_2darray::init_color_and_transparency() {
	// we do nothing here
	// in container vm, we ignore the inports RGB
	// typically, the child vms have their own color

}
void ubvm_2darray::update_color_and_transparency() {
	init_color_and_transparency();
}
string ubvm_2darray::replace_clickmsg() {

	string original = _vm_clickmsg_val ;
	string result = "" ;
	size_t first = 0 ;
	size_t last = original.find("@");

	while(last != string::npos){
		result = result + original.substr(first,last-first);
		first = last;
		last++;
		bool match = false;

		// check if the character behind @ is a number
		while(original[last] > 47 && original[last] < 58){ 
			match = true;
			last++;			
		}
		if(match){
			// string sub = original.substr(first,last-first);
			result = result + _indexinfo ;
		}
		first = last ;
		last = original.find("@",first);		
	}
	result = result + original.substr(first);
	return result ;
}
void ubvm_2darray::VMSetVisible(bool vis) {
	if (_visible != vis) {
		  _visible = vis ;
         _SceneNode->setVisible(vis);
	}
	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		DIVA_VM *vm = (*itr);
		vm->VMSetVisible(vis);
	}
		
}
void ubvm_2darray::VMDragged(Ogre::Real screenx,Ogre::Real screeny, Ogre::Real absx,Ogre::Real absy,Ogre::Real absz) {
	// a container contains a lot of child VMs.
	// (x,y,z) are the place which is clicked but it is not necessary the center of the container VM
	// when the first time a VM is picked, we save the position of the container scene node

	if (_freshclick) {
		_dist = Ogre::Vector3(absx,absy,absz) - _center ;
		_freshclick = false;
	}
	if (isDraggedOn()) {
		Ogre::Vector3 newcenter = Ogre::Vector3(absx,absy,absz) - _dist ;
		this->setPosition(newcenter);
	}
}
void ubvm_2darray::VMPicked(Ogre::Real x, Ogre::Real y, Ogre::Real z) {
	_center  = getPosition();
	_freshclick = true ;
	
	int current_hit = 0;
	current_hit = VL_propagateMouseEvent(_child_vms,Ogre::Vector3(x,y,z));
	int row = current_hit / (*_columns) ;
	int column = current_hit % (*_rows) ;

	std::ostringstream oss ;
	oss << "@ (" << row << "," << column << ")" ;
	_indexinfo = oss.str(); 
	DIVA_VM::VMPicked(x,y,z); // called the default implementation to show the clickmsg

}
void ubvm_2darray::VMValueUpdated() {
	DIVA_VM::VMValueUpdated();
}
bool ubvm_2darray::isSubComponent(DIVA_VM *vm) {
	
	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		DIVA_VM *kid=(*itr);
		if (kid->isSubComponent(vm)) return true ;
	}
	return false ;
}

void ubvm_2darray::scaleBodyToAbsSize(Ogre::Vector3 v){
	setBodyScale(Ogre::Vector3(v.x/_vm_init_sizex,
		                 v.y/_vm_init_sizey,
						 v.z/_vm_init_sizez));
}
void ubvm_2darray::setBodyScale(Ogre::Vector3 scale) {
	_SceneNode->setScale(scale);
}
bool ubvm_2darray::isBodyScaleWrtSceneNode() { return true ; }

Ogre::Vector3 ubvm_2darray::getOriginalBodySize() {
	return Ogre::Vector3(_vm_init_sizex, _vm_init_sizey, _vm_init_sizez) ;
}

Ogre::Vector3 ubvm_2darray::getActualSize() {
	return getBoundingBoxSize();
}
Ogre::Vector3 ubvm_2darray::getBodyScale() {
	return _SceneNode->getScale();
}

Ogre::Vector3 ubvm_2darray::getBoundingBoxSize(){
	
	Ogre::Vector3 max=Ogre::Vector3(0,0,0);
	Ogre::Vector3 min=Ogre::Vector3(0,0,0);

	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		
		Ogre::Vector3 pos=(*itr)->getPosition();
		Ogre::Vector3 size=(*itr)->getActualSize();

		if (pos.x+size.x/2 >= max.x) max.x = pos.x+size.x/2;
		if (pos.x-size.x/2 <= min.x) min.x = pos.x-size.x/2;
		if (pos.y+size.y/2 >= max.y) max.y = pos.y+size.y/2;
		if (pos.y-size.y/2 <= min.y) min.y = pos.y-size.y/2;
		if (pos.z+size.z/2 >= max.z) max.z = pos.z+size.z/2;  
		if (pos.z-size.z/2 <= min.z) min.z = pos.z-size.z/2;

		// (*itr)->setPosition(pos);
	}

	Ogre::Vector3 bb;
	bb.x=max.x-min.x; assert(bb.x>=0);
	bb.y=max.y-min.y; assert(bb.y>=0);
	bb.z=max.z-min.z; assert(bb.z>=0);
	
	//this->scaleBodyToAbsSize(container_size*2.2);
	return bb ;
}
